<?php

namespace Tasker\Models;

class TasksModel extends BaseModel
{

	public function getTasksCount($user)
	{
		$tasks = $this->connection->task('worker_id', $user)->where('task_status.completed', 'no');
		$count = count($tasks);
		return $count;
	}

	public function getTasks($user = FALSE, $where=array())
	{
		$tasks = $this->connection->task()->where($where);
		if ($user !== FALSE)
			$tasks = $tasks->where('worker_id', $user)->where('task_status.completed', 'no');

		return $tasks;
	}

	public function getAssignedTasksCount($user)
	{
		$tasks = $this->connection->task('creator_id', $user)->where('task_status.completed', 'no');
		$count = count($tasks);
		return $count;
	}

	public function getAssignedTasks($user, $where=array())
	{
		return $this->connection->task('creator_id', $user)->where('task_status.completed', 'no');
	}

	public function getCompletedHistory($task)
	{
		return $this->connection->task_completed_history('id_task', $task);
	}

	public function getLastComments($user)
	{
		$requiredIds = $this->connection->task()->where('worker_id = ' . $user . ' OR creator_id = ' . $user);
		return $this->connection->task_comment()->where('task_id', $requiredIds)->order('date DESC');
	}

	public function getUsedWorkers()
	{
		return $this->connection->task()->select('distinct worker.*')->order('worker.surname, worker.name');
	}

	public function getUsedCreators()
	{
		return $this->connection->task()->select('distinct creator.*')->order('creator.surname, creator.name');
	}

	public function getWatchedTasks($userId)
	{
		return $this->connection->watched_task()->where('user_id', $userId);
	}

	public function addTask($values)
	{
		$values = (array) $values;
		$prerequisites = $values['prerequisites'];
		$values['completed'] = 0;
		unset($values['id'], $values['prerequisites']);
		$pretasks = array_keys($prerequisites);
		$task = $this->connection->task()->insert($values);
		if ($task === null)
			return false;

		foreach ($prerequisites as $prerequisite => $details)
		{
			$prereq_values = array(
				'task_id' => $task['id'],
				'prerequisite_id' => $prerequisite,
				'dependency_type' => $details['role'],
			);
			$this->connection->prerequisite_task()->insert($prereq_values);
		}

		$task->update(array('level' => $this->calculateLevel($task['id'])));

		$status_values = array(
			'task_status_id' => $values['task_status_id'],
			'task_id' => $task['id'],
			'date' => new \DateTime(),
			'user_id' => $values['creator_id'],
		);
		$this->connection->task_status_history()->insert($status_values);
		$completed_values = array(
			'task_id' => $task['id'],
			'date' => new \DateTime(),
			'completed' => 0,
			'user_id' => $values['creator_id'],
			'info' => 'Vytvoření úkolu'
		);
		$this->connection->task_completed_history()->insert($completed_values);

		return true;
	}

	public function editTask($values)
	{
		$values = (array) $values;
		$id = $values['id'];
		$prerequisites = $values['prerequisites'];
		unset($values['id'], $values['prerequisites']);

		$this->connection->prerequisite_task()->where('task_id', $id)->delete();

		foreach ($prerequisites as $prerequisite => $details)
		{
			$prereq_values = array(
				'task_id' => $id,
				'prerequisite_id' => $prerequisite,
				'dependency_type' => $details['role'],
			);
			$this->connection->prerequisite_task()->insert($prereq_values);
		}
		$this->recalculateLevels($values['project_id']);

		$task = $this->connection->task[$id];
		$result = $task->update($values);
		if ($result === false)
			return false;

		if ($task['task_status_id'] != $values['task_status_id'])
		{
			$status_values = array(
				'task_status_id' => $values['task_status_id'],
				'task_id' => $task['id'],
				'date' => new \DateTime(),
				'user_id' => $values['creator_id'],
			);
			$this->connection->task_status_history()->insert($status_values);
		}
		return true;
	}

	public function getWatched(array $where=array())
	{
		return $this->connection->watched_task()->where($where);
	}

	public function addWatched($user, $task)
	{
		return $this->connection->watched_task()->insert(array('user_id' => $user, 'task_id' => $task));
	}

	public function deleteWatched($user, $task)
	{
		return $this->connection->watched_task()->where(array('user_id' => $user, 'task_id' => $task))->delete();
	}

	public function recalculateLevels($project)
	{
		// Set all levels to 0
		$this->connection->task()->where('project_id', $project)->update(array('level' => 0));
		// Find tasks without prerequisites
		$tmp = $this->connection->task()->where('project_id', $project)->where('NOT id', $this->connection->prerequisite_task()->select('task_id'))->select('id');
		// Save task ids to array (queue)
		$tasks = array_keys(iterator_to_array($tmp));
		// Get first value from array
		$value = reset($tasks);
		// Variable for endless loop protection
		$i = 0;
		// Loop while there is a value in the array
		while ($value)
		{
			// Get current task
			$task = $this->connection->task[$value];
			// Calculate level for this task
			$calculatedLevel = $this->calculateLevel($value);
			// If new level is bigger that level calculated before
			if ($calculatedLevel > $task['level'])
			{
				// Update task
				$task->update(array('level' => $calculatedLevel));
			}
			// Find tasks which are depended on actual task
			$tmp = $this->connection->prerequisite_task()->where('prerequisite_id', $value)->select('task_id');
			// And push them into queue
			foreach ($tmp as $t)
			{
				$tasks[] = (int) $t['task_id'];
			}
			// Get next value from queue
			$value = next($tasks);
			// endless loop protection - one milion tasks seems to be enought :)
			if ($i++ > 1e6)
				return false;
		}
		return true;
	}

	private function calculateLevel($task)
	{
		$level = $this->connection->prerequisite_task('task_id', $task)->max("CASE dependency_type WHEN 'start-to-start' THEN prerequisite.level WHEN 'start-to-finish' THEN level-1 WHEN 'finish-to-finish' THEN level WHEN 'finish-to-start' THEN level+1 END");
		return (int) $level;
	}

	
	public function addComment($values)
	{
		$values = (array)$values;
		return $this->connection->task_comment()->insert($values);
	}
}
